package com.googlecode.librank.tgf;

import java.io.BufferedReader;
import java.io.FileReader;
import java.io.IOException;
import java.io.PrintStream;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashSet;
import java.util.Hashtable;
import java.util.List;
import java.util.Set;

import com.googlecode.librank.util.HashCount;

public class ParseProjectLibname {
	final static int CUTOFF = 7;
	List<Project> projectList = null;
	HashCount<String> libraryNameCount = null;
	Hashtable<String, Integer> libraryOrder = null;

	List<Project> readProjects(String fileName) throws IOException {
		projectList = new ArrayList<Project>();
		libraryNameCount = new HashCount<String>();

		BufferedReader br = new BufferedReader(new FileReader(fileName));
		Project currrentProject = new Project("");
		while (true) {
			String line = br.readLine();
			if (line == null) {
				break;
			}

			String splits[] = line.split("\\s+");
			if (splits.length != 2) {
				System.err.println("Cannot parse: " + line);
				continue;
			}

			String projectName = splits[0];
			String libraryName = splits[1];
			// new same project
			if (!projectName.equals(currrentProject.name)) {
				currrentProject = new Project(projectName);
				projectList.add(currrentProject);
			}

			// add the library to corresponding project
			currrentProject.addLibrary(libraryName);

			// add the library name to hashcount
			libraryNameCount.increase(splits[1]);

		}
		br.close();

		return projectList;
	}

	void generateTGFFile() {
		PrintStream out = System.out;

		assert (projectList != null);
		assert (libraryNameCount != null);

		for (Project project : projectList) {
			for (String libName : project.libraries) {
				// ignore java.*
				if (neglectableLibrary(libName)) {
					continue;
				}

				out.println(project.name + " " + libName);
			}
		}
	}

	/**
	 * Check if the given library is neglectable
	 * 
	 * @return
	 */
	private boolean neglectableLibrary(String libName) {
		// ignore java.*
		if (libName.startsWith("java.") || libName.startsWith("javax.")) {
			return true;
		}

		if (libraryNameCount.getCount(libName) < CUTOFF) {
			return true;
		}

		return false;
	}

	void generateLibDependancyTGF() {
		PrintStream out = System.out;

		assert (projectList != null);
		assert (libraryNameCount != null);

		Set<String> uniqueSet = new HashSet<String>();

		for (Project project : projectList) {
			for (int i = 0; i < project.libraries.size(); i++) {
				String libName = project.libraries.get(i);
				if (neglectableLibrary(libName)) {
					continue;
				}

				for (int j = i + 1; j < project.libraries.size(); j++) {
					String libName2 = project.libraries.get(j);

					if (neglectableLibrary(libName2)) {
						continue;
					}

					String output = (libName + " " + libName2);
					out.println(output);

					uniqueSet.add(output);

				}
			}
		}

		out.println("#\n## Unique set\n#");
		for (String output : uniqueSet) {
			out.println(output);
		}
	}

	public void generateWekaFile() {
		PrintStream out = System.out;

		// phase 3: generating arff file
		List<String> libNameList = libraryNameCount.getKeyList();
		Collections.sort(libNameList);
		out.println("@RELATION project-class");

		libraryOrder = new Hashtable<String, Integer>();

		// print ATTRIBUTES and builds hashtable
		int index = 0;
		for (String libName : libNameList) {
			if (libraryNameCount.getCount(libName) < CUTOFF) {
				continue;
			}

			out.println("@ATTRIBUTE " + libName + " {0, 1}");
			libraryOrder.put(libName, index++);
		}

		out.println("@DATA");

		for (Project project : projectList) {
			// Sort the library name
			Collections.sort(project.libraries);

			out.print("{");
			boolean doesDataOut = false;
			for (String libName : project.libraries) {
				Integer order = libraryOrder.get(libName);
				if (order != null) {
					if (doesDataOut) {
						out.print(",");
					} else {
						doesDataOut = true;
					}
					out.print(order + " 1");
				}
			}

			out.println("}");
		}
	}

	public static void main(String[] args) throws IOException {
		ParseProjectLibname parser = new ParseProjectLibname();
		parser.readProjects(args[0]);

		parser.generateTGFFile();
		parser.generateWekaFile();
		parser.generateLibDependancyTGF();
	}
}
